fix FileSystem::setModTime on x64 Windows with times > 2038
authorJyrki Gadinger <nilsding@nilsding.org>
Tue, 8 Apr 2025 11:09:18 +0000 (13:09 +0200)
committerbackportbot[bot] <backportbot[bot]@users.noreply.github.com>
Wed, 9 Apr 2025 07:13:22 +0000 (07:13 +0000)
also removes some unused Utility methods

Signed-off-by: Jyrki Gadinger <nilsding@nilsding.org>
src/common/utility.h
src/common/utility_win.cpp
src/csync/std/c_time.cpp
src/csync/std/c_time.h
src/libsync/filesystem.cpp

index 167eb6b8e668bcaaa6a21459bcaebc750415d0b9..dccfd044cb9cb9bb29a59d774d99da48349d8906 100644 (file)
@@ -294,9 +294,6 @@ namespace Utility {
     OCSYNC_EXPORT bool registryWalkValues(HKEY hRootKey, const QString &subKey, const std::function<void(const QString &, bool *)> &callback);
     OCSYNC_EXPORT QRect getTaskbarDimensions();
 
-    // Possibly refactor to share code with UnixTimevalToFileTime in c_time.c
-    OCSYNC_EXPORT void UnixTimeToFiletime(time_t t, FILETIME *filetime);
-    OCSYNC_EXPORT void FiletimeToLargeIntegerFiletime(FILETIME *filetime, LARGE_INTEGER *hundredNSecs);
     OCSYNC_EXPORT void UnixTimeToLargeIntegerFiletime(time_t t, LARGE_INTEGER *hundredNSecs);
 
     OCSYNC_EXPORT QString formatWinError(long error);
index e2b917028fd11417445aa1ce07228daf4139ff42..eb3d57d5b3d5a6534b23bc13b7eca03550d91369 100644 (file)
@@ -483,24 +483,9 @@ DWORD Utility::convertSizeToDWORD(size_t &convertVar)
     return static_cast<DWORD>(convertVar);
 }
 
-void Utility::UnixTimeToFiletime(time_t t, FILETIME *filetime)
-{
-    LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
-    filetime->dwLowDateTime = (DWORD) ll;
-    filetime->dwHighDateTime = ll >>32;
-}
-
-void Utility::FiletimeToLargeIntegerFiletime(FILETIME *filetime, LARGE_INTEGER *hundredNSecs)
-{
-    hundredNSecs->LowPart = filetime->dwLowDateTime;
-    hundredNSecs->HighPart = filetime->dwHighDateTime;
-}
-
 void Utility::UnixTimeToLargeIntegerFiletime(time_t t, LARGE_INTEGER *hundredNSecs)
 {
-    LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
-    hundredNSecs->LowPart = (DWORD) ll;
-    hundredNSecs->HighPart = ll >>32;
+    hundredNSecs->QuadPart = (t * 10000000LL) + 116444736000000000LL;
 }
 
 bool Utility::canCreateFileInPath(const QString &path)
index b51b5a2d1a0cba6a1f0d1c15fbc052343d123fdf..5281efa9a6892e360ac48d75314ca8f626f5669d 100644 (file)
 #include <QFile>
 
 #ifdef HAVE_UTIMES
-int c_utimes(const QString &uri, const struct timeval *times) {
-    int ret = utimes(QFile::encodeName(uri).constData(), times);
-    return ret;
+int c_utimes(const QString &uri, const time_t time)
+{
+    struct timeval times[2];
+    times[0].tv_sec = times[1].tv_sec = time;
+    times[0].tv_usec = times[1].tv_usec = 0;
+    return utimes(QFile::encodeName(uri).constData(), times);
 }
+
 #else // HAVE_UTIMES
 
 #ifdef _WIN32
-// implementation for utimes taken from KDE mingw headers
+// based on the implementation for utimes from KDE mingw headers
 
 #include <errno.h>
 #include <wtypes.h>
-#define CSYNC_SECONDS_SINCE_1601 11644473600LL
-#define CSYNC_USEC_IN_SEC            1000000LL
-//after Microsoft KB167296
-static void UnixTimevalToFileTime(struct timeval t, LPFILETIME pft)
+
+constexpr long long CSYNC_SECONDS_SINCE_1601 = 11644473600LL;
+constexpr long long CSYNC_USEC_IN_SEC = 1000000LL;
+
+// after Microsoft KB167296, except it uses a `time_t` instead of a `struct timeval`.
+//
+// `struct timeval` is defined in the winsock.h header of all places, and its fields are two `long`s,
+// which even on x64 Windows is 4 bytes wide (i.e. int32).  `time_t` on the other hand is 8 bytes
+// wide (int64) on x64 Windows as well.
+static void UnixTimeToFiletime(const time_t time, LPFILETIME pft)
 {
-    LONGLONG ll = 0;
-    ll = Int32x32To64(t.tv_sec, CSYNC_USEC_IN_SEC*10) + t.tv_usec*10 + CSYNC_SECONDS_SINCE_1601*CSYNC_USEC_IN_SEC*10;
+    LONGLONG ll = time * CSYNC_USEC_IN_SEC * 10 + CSYNC_SECONDS_SINCE_1601 * CSYNC_USEC_IN_SEC * 10;
     pft->dwLowDateTime = (DWORD)ll;
     pft->dwHighDateTime = ll >> 32;
 }
 
-int c_utimes(const QString &uri, const struct timeval *times) {
-    FILETIME LastAccessTime;
-    FILETIME LastModificationTime;
+int c_utimes(const QString &uri, const time_t time)
+{
+    FILETIME filetime;
     HANDLE hFile = nullptr;
 
     auto wuri = uri.toStdWString();
 
-    if(times) {
-        UnixTimevalToFileTime(times[0], &LastAccessTime);
-        UnixTimevalToFileTime(times[1], &LastModificationTime);
-    }
-    else {
-        GetSystemTimeAsFileTime(&LastAccessTime);
-        GetSystemTimeAsFileTime(&LastModificationTime);
-    }
+    UnixTimeToFiletime(time, &filetime);
 
     hFile=CreateFileW(wuri.data(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                       nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS, nullptr);
@@ -87,7 +89,7 @@ int c_utimes(const QString &uri, const struct timeval *times) {
         return -1;
     }
 
-    if(!SetFileTime(hFile, nullptr, &LastAccessTime, &LastModificationTime)) {
+    if (!SetFileTime(hFile, nullptr, &filetime, &filetime)) {
         //can this happen?
         errno=ENOENT;
         CloseHandle(hFile);
index 55a6aa6bc836f7226972b7f8b18f82e57e9c656a..7d3d862a995592defd5224c8f50721005f7d688c 100644 (file)
@@ -31,7 +31,7 @@
 #include <sys/time.h>
 #endif
 
-OCSYNC_EXPORT int c_utimes(const QString &uri, const struct timeval *times);
+OCSYNC_EXPORT int c_utimes(const QString &uri, time_t time);
 
 
 #endif /* _C_TIME_H */
index 5b719bd8be645d257b95e64ffc19f108593e4510..59f375ed246abf701a8aa4f360d3e363ed1627b2 100644 (file)
@@ -196,10 +196,7 @@ time_t FileSystem::getModTime(const QString &filename)
 
 bool FileSystem::setModTime(const QString &filename, time_t modTime)
 {
-    struct timeval times[2];
-    times[0].tv_sec = times[1].tv_sec = modTime;
-    times[0].tv_usec = times[1].tv_usec = 0;
-    int rc = c_utimes(filename, times);
+    int rc = c_utimes(filename, modTime);
     if (rc != 0) {
         qCWarning(lcFileSystem) << "Error setting mtime for" << filename
                                 << "failed: rc" << rc << ", errno:" << errno;